/*
 * Copyright (C) 2025 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the 'License');
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an 'AS IS' BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <string>
#include "imageknife_decoder_avif.h"
#include "api/imageknife_api.h"
#include "log.h"
#include "securec.h"
#include "number_constant.h"

namespace ImageKnifePro {

bool ImageKnifeDecoderAvif::IsAvifEnable()
{
    return true;
}

ImageKnifeDecoderAvif::ImageKnifeDecoderAvif()
{
    (void)memset_s(&rgbImage_, sizeof(avifRGBImage), 0, sizeof(avifRGBImage));
}

ImageKnifeDecoderAvif::~ImageKnifeDecoderAvif()
{
    if (decoder_ != nullptr) {
        avifDecoderDestroy(decoder_);
    }
    avifRGBImageFreePixels(&rgbImage_);
}

uint32_t ImageKnifeDecoderAvif::GetWidth() const
{
    if (decoder_ != nullptr && decoder_->image != nullptr) {
        return decoder_->image->width;
    }
    return 0;
}

uint32_t ImageKnifeDecoderAvif::GetHeight() const
{
    if (decoder_ != nullptr && decoder_->image != nullptr) {
        return decoder_->image->height;
    }
    return 0;
}

uint32_t ImageKnifeDecoderAvif::GetFrameCount() const
{
    if (decoder_ != nullptr && decoder_->imageCount > 0) {
        return decoder_->imageCount;
    }
    return 0;
}

std::shared_ptr<int []> ImageKnifeDecoderAvif::GetDelayTimeList() const
{
    return delayTimeList_;
}

std::string ImageKnifeDecoderAvif::Init(uint8_t *buffer, uint32_t length)
{
    if (buffer == nullptr || length == 0) {
        return "file buffer invalid";
    }

    decoder_ = avifDecoderCreate();
    if (decoder_ == nullptr) {
        return "avif decoder create failed";
    }

    avifResult result = avifDecoderSetIOMemory(decoder_, buffer, length);
    if (result != AVIF_RESULT_OK) {
        avifDecoderDestroy(decoder_);
        decoder_ = nullptr;
        return "avif set image buffer failed:" + std::to_string(result);
    }

    result = avifDecoderParse(decoder_);
    if (result != AVIF_RESULT_OK) {
        avifDecoderDestroy(decoder_);
        decoder_ = nullptr;
        return "avif parse image buffer failed:" + std::to_string(result);
    }

    // 获取帧播放时长列表
    if (decoder_->imageCount > 1) {
        int *timeListOut = new int [decoder_->imageCount];
        (void)memset_s(timeListOut, sizeof(int) * decoder_->imageCount, 0, sizeof(int) * decoder_->imageCount);
        auto deleter = [](void *data) {
            int *timeList = static_cast<int *>(data);
            delete [] timeList;
        };
        delayTimeList_ = std::shared_ptr<int []>(timeListOut, deleter);

        const int thousand = 1000;
        avifImageTiming imageTiming;
        for (int i = 0; i < decoder_->imageCount; i++) {
            imageTiming.duration = 0;
            (void)avifDecoderNthImageTiming(decoder_, i, &imageTiming);
            timeListOut[i] = imageTiming.duration * thousand;
        }
    }

    return std::string();
}

// 大于8位宽的图片，avif以uint16存储，而oh_pixelmap无对应的pixelmap format需要转换
void CovertToRGBA8888(const avifRGBImage &rgbImage, std::vector<uint8_t> &outData)
{
    IMAGE_KNIFE_CHECK(outData.size() < rgbImage.width * rgbImage.height * NUM_4);
    uint16_t *data = reinterpret_cast<uint16_t *>(rgbImage.pixels);
    IMAGE_KNIFE_CHECK(data == nullptr);
    size_t byteGap = rgbImage.depth - NUM_8;

    for (int y = 0; y < rgbImage.height; ++y) {
        for (int x = 0; x < rgbImage.width; ++x) {
            size_t pos = (y * rgbImage.width + x) * NUM_4;
            // 单像素缩放至8b
            outData[pos] = data[pos] >> byteGap;
            outData[pos + 1] = data[pos + 1] >> byteGap;
            outData[pos + NUM_2] = data[pos + NUM_2] >> byteGap;
            outData[pos + NUM_3] = data[pos + NUM_3] >> byteGap;
        }
    }
}

std::string ImageKnifeDecoderAvif::DecodeFrame(uint32_t frameIndex, OH_PixelmapNative **pixelmapOut)
{
    if (decoder_ == nullptr) {
        return "decoder is nullptr";
    }

    if (pixelmapOut == nullptr) {
        return "pixelmapOut is nullptr";
    }

    avifResult result = avifDecoderNthImage(decoder_, frameIndex);
    if (result != AVIF_RESULT_OK) {
        return "decoder frame: " + std::to_string(frameIndex) + " failed:" + std::to_string(result);
    }
    IMAGE_KNIFE_CHECK_RETURN(decoder_->image == nullptr, "avif decoder error: image is nullptr");

    if (decoder_->image->width != desiredWidth_ && decoder_->image->height != desiredHeight_ &&
        desiredWidth_ != 0 && desiredHeight_ != 0) {
        avifDiagnostics diag;
        result = avifImageScale(decoder_->image, desiredWidth_, desiredHeight_, &diag);
        if (result != AVIF_RESULT_OK) {
            IMAGE_KNIFE_LOG(LOG_ERROR, "Avif Scale Failed: %{public}d %{public}s", result, diag.error);
        }
    }

    avifRGBImageSetDefaults(&rgbImage_, decoder_->image);
    result = avifRGBImageAllocatePixels(&rgbImage_);
    if (result != AVIF_RESULT_OK) {
        return "decoder frame: " + std::to_string(frameIndex) + " Allocation failed:" + std::to_string(result);
    }

    result = avifImageYUVToRGB(decoder_->image, &rgbImage_);
    if (result != AVIF_RESULT_OK) {
        return "decoder frame: " + std::to_string(frameIndex) + " Conversion YUV failed:" + std::to_string(result);
    }

    return CreatePixelmapNative(pixelmapOut);
}

std::string ImageKnifeDecoderAvif::CreatePixelmapNative(OH_PixelmapNative **pixelmapOut)
{
    IMAGE_KNIFE_CHECK_RETURN(rgbImage_.pixels == nullptr, "avif error: image pixel is nullptr");
    OH_Pixelmap_InitializationOptions *options = nullptr;
    Image_ErrorCode errorCode = OH_PixelmapInitializationOptions_Create(&options);
    if (errorCode != IMAGE_SUCCESS) {
        return "Create pixelmap initialization options failed:" + std::to_string(errorCode);
    }

    OH_PixelmapInitializationOptions_SetWidth(options, rgbImage_.width);
    OH_PixelmapInitializationOptions_SetHeight(options, rgbImage_.height);
    OH_PixelmapInitializationOptions_SetPixelFormat(options, PIXEL_FORMAT_RGBA_8888);
    OH_PixelmapInitializationOptions_SetSrcPixelFormat(options, PIXEL_FORMAT_RGBA_8888);

    std::vector<uint8_t> rgbaVec;
    uint8_t *pixels = rgbImage_.pixels;
    size_t dataLength = rgbImage_.width * rgbImage_.height * NUM_4;
    if (rgbImage_.depth > NUM_8) {
        rgbaVec.resize(dataLength);
        CovertToRGBA8888(rgbImage_, rgbaVec);
        pixels = rgbaVec.data();
    }

    // 尝试为创建DMA内存
    static auto CreatePixelmapFunc = ImageKnifeApi::GetInstance().GetPixelmapApi().GetCreatePixelmapUsingAllocator();
    if (CreatePixelmapFunc != nullptr) {
        errorCode = CreatePixelmapFunc(pixels, dataLength, options, allocationMode_, pixelmapOut);
        // 如果指定的内存申请模式不支持，则退回使用自动模式兼容
        if (errorCode == IMAGE_SOURCE_UNSUPPORTED_ALLOCATOR_TYPE) {
            errorCode = CreatePixelmapFunc(pixels, dataLength, options, IMAGE_ALLOCATOR_MODE_AUTO, pixelmapOut);
        }
    } else {
        errorCode = OH_PixelmapNative_CreatePixelmap(pixels, dataLength, options, pixelmapOut);
    }

    OH_PixelmapInitializationOptions_Release(options);
    avifRGBImageFreePixels(&rgbImage_);
    if (errorCode != IMAGE_SUCCESS) {
        return "Create pixelmap by rgbImage failed:" + std::to_string(errorCode);
    }

    return std::string();
}

void ImageKnifeDecoderAvif::SetAllocationMode(AllocationMode mode)
{
    allocationMode_ = static_cast<IMAGE_ALLOCATOR_MODE>(mode);
}

void ImageKnifeDecoderAvif::SetDesiredImageSize(Image_Size imageSize)
{
    desiredWidth_ = imageSize.width;
    desiredHeight_ = imageSize.height;
}

}